/**
 * @ngdoc overview
 * @name workflow.services
 * @description
 *   工作流模块服务
 */
angular.module('workflow.services', [])

/**
 * @ngdoc service
 * @name workflow.services.Flow
 * @description
 *   工作流通用服务
 */
.factory('Flow', function($rootScope, $http, $ionicLoading, Utils, Settings, User, IbPopup) {
  var getModuleUrl = function () {
    return Settings.rootUrl + '/work';
  }

  var ret = {
    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#create
     * @methodOf    workflow.services.Flow
     * @description
     *   新建工作流
     *   res.isSuccess  {Boolean}
     *   res.key        {String}
     *
     * @param       {String}   flowid    工作流程类型 id
     * @returns     {Promise}
     */
    create: function(flowid) {
      return $http.get(getModuleUrl() + '/add', {
          params: {
            flowid: flowid
          }
        })
        .success(function(res) {
          $rootScope.$broadcast('workflow.create', flowid, res);
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#getFlow
     * @methodOf    workflow.services.Flow
     * @description
     *   获取工作流数据，包括表单数据、附件、会签、进度等信息
     *
     * @param       {String}   key     工作流 key
     * @param       {Object}   param   额外参数
     * @returns     {Promise}
     */
    getFlow: function(key, params) {
      params = params || {};
      params.key = key;
      return $http.get(getModuleUrl() + '/form', {
          params: params
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#getProcess
     * @methodOf    workflow.services.Flow
     * @description
     *   获取流程列表及分类数据
     *
     * @returns     {Promise}
     */
    getProcess: function() {
      return $http.get(getModuleUrl() + '/new')
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#saveFlow
     * @methodOf    workflow.services.Flow
     * @description
     *   保存工作流表单数据
     *
     * @param       {Object}   data   表单数据
     * @returns     {Promise}
     */
    saveFlow: function(data) {
      var formData = new FormData()
      angular.forEach(data, function(value, key) {
        formData.append(key, value)
      })

      return Utils.postFormData(getModuleUrl() + '/form', formData)
        .success(function(res) {
          $rootScope.$broadcast('workflow.saveFlow', data, res);
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#getNext
     * @methodOf    workflow.services.Flow
     * @description
     *   获取转交所需的数据
     *   params.key  {string}  流程 key
     *   params.topflag  {string}  标识
     * @param       {object}   params   参数
     * @returns     {Promise}
     */
    getNext: function(params) {
      return $http.get(getModuleUrl() + '/shownext', {
          params: params
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#getFreeNext
     * @methodOf    workflow.services.Flow
     * @description
     *   获取自由流程转交所需的数据
     *
     * @param       {String}   key   流程 key
     * @returns     {Promise}
     */
    getFreeNext: function(key) {
      return $http.get(getModuleUrl() + '/freenext', {
          params: {
            key: key
          }
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#rollback
     * @methodOf    workflow.services.Flow
     * @description
     *   回退工作流至上一步骤
     *
     * @param       {String}   key    流程 key
     * @param       {Object}   data   参数
     * @returns     {Promise}
     */
    rollback: function(key, data) {
      return $http.post(getModuleUrl() + '/fallback&key=' + key, data)
        .success(function(res) {
          if (res.isSuccess) {
            $rootScope.$broadcast('workflow.rollback', key, data, res);
          }
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#takeback
     * @methodOf    workflow.services.Flow
     * @description
     *   在下一步骤被接收前，收回工作流
     *
     * @param       {String}   key    流程 key
     * @returns     {Promise}
     */
    takeback: function(key) {
      return $http.post(getModuleUrl() + '/takeback&key=' + key)
        .success(function(res) {
          if (res.isSuccess) {
            $rootScope.$broadcast('workflow.takeback', key, res);
          }
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#confirmTakeback
     * @methodOf    workflow.services.Flow
     * @description
     *   确认提示后收回工作流
     *
     * @param       {Object}   flow    流程数据
     */
    confirmTakeback: function(flow) {
      var _this = this;

      IbPopup.confirm({
          title: '下一步骤尚未接收时可收回至本步骤重新办理，确认要收回吗？'
        })
        .then(function(res) {
          if (res) {
            $ionicLoading.show();
            _this.takeback(flow.key)
              .finally($ionicLoading.hide);
          }
        });
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#handover
     * @methodOf    workflow.services.Flow
     * @description
     *   转交工作流至下一步骤
     *
     * @param       {Object}   data    转交参数
     * @returns     {Promise}
     */
    handover: function(data) {
      return $http.post(getModuleUrl() + '/turnNextPost', data)
        .success(function(res) {
          if (res.isSuccess) {
            $rootScope.$broadcast('workflow.handover', data, res);
          }
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#handoverFree
     * @methodOf    workflow.services.Flow
     * @description
     *   转交自由流程至下一步骤
     *
     * @param       {Object}   data    转交参数
     * @returns     {Promise}
     */
    handoverFree: function(data) {
      return $http.post(getModuleUrl() + '/freenext', data)
        .success(function(res) {
          $rootScope.$broadcast('workflow.handoverFree', data, res);
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#signFlow
     * @methodOf    workflow.services.Flow
     * @description
     *   经办人会签（办理完毕）
     *
     * @param       {String}   key    流程 key
     * @param       {Object}   data    会签参数
     * @returns     {Promise}
     */
    signFlow: function(key, params) {
      params = params || {};
      params.key = key;
      return $http.get(getModuleUrl() + '/complete', {
          params: params
        })
        .success(function(res) {
          $rootScope.$broadcast('workflow.signFlow', params, res);
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#remove
     * @methodOf    workflow.services.Flow
     * @description
     *   删除流程
     *
     * @param       {String}   id      工作流 id
     * @returns     {Promise}
     */
    remove: function(id) {
      return $http.post(getModuleUrl() + '/del', {
          id: id
        })
        .success(function(res) {
          if (res.isSuccess) {
            $rootScope.$broadcast('workflow.remove', id, res);
          }
        })
        .error(Settings.requestError);
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#confirmRemove
     * @methodOf    workflow.services.Flow
     * @description
     *   确认后删除流程
     *
     * @param       {String}   flow      工作流数据
     * @returns     {Promise}
     */
    confirmRemove: function(flow) {
      var _this = this;

      IbPopup.confirm({
          title: '确定要删除该工作吗？'
        })
        .then(function(res) {
          if (res) {
            // $ionicLoading.show();
            _this.remove(flow.runid);
            // .finally($ionicLoading.hide);
          }
        });
    },

  };

  return ret;
})

/**
 * @ngdoc service
 * @name workflow.services.FlowUtils
 * @description
 *   工作流通用工具函数
 */
.factory('FlowUtils', function($timeout, $state, $ionicHistory, IbPopup) {
  return {
    /**
     * @ngdoc     method
     * @name      workflow.services.FlowUtils#goBackOrHome
     * @methodOf  workflow.services.FlowUtils
     * @description
     *   如果有后退页，则后退，没有则回工作流首页
     */
    goBackOrHome: function() {
      if ($ionicHistory.backView()) {
        $ionicHistory.goBack();
      } else {
        $ionicHistory.nextViewOptions({
          disableBack: true
        });
        $state.go('workflow.index');
      }
    },

    /**
     * @ngdoc       method
     * @name        workflow.services.Flow#onHandoverSuccess
     * @methodOf    workflow.services.Flow
     * @description
     *   转交成功后的回调
     *
     * @param       {Object}   res   转交成功后返回的数据
     * @returns     {Promise}
     */
    onHandoverSuccess: function(res) {
      if (res.isSuccess) {

        var popup = IbPopup.alert({
          title: '转交成功'
        })

        popup.then(function() {
          $ionicHistory.clearCache(['workflow.todo', 'workflow.trans', 'workflow.done'])
          $ionicHistory.nextViewOptions({
            disableBack: true
          });
          var backViewStateId = $ionicHistory.backView().stateId
          var currentViewStateId = $ionicHistory.currentView().stateId
          $state.go('workflow.index').then(function() {
            $ionicHistory.clearCache([backViewStateId, currentViewStateId])
          })

          // 成功后清缓存

        });

        $timeout(popup.close.bind(popup), 2000);

      } else {
        IbPopup.alert({
          title: res.msg
        });
      }
    }
  }
})

.factory('FlowListUtil', function() {
  return {

    // 根据工作流 key 删除列表中对应的项
    removeByKey: function(key) {
      var _this = this;

      if (!this.items.length) {
        return;
      }

      angular.forEach(this.items, function(item, i) {
        if (item.key == key) {
          _this.items.splice(i, 1);
          return false;
        }
      });
    }
  };
})

/**
 * @ngdoc service
 * @name workflow.services.FlowTodo
 * @description
 *   待办工作列表数据
 */
.factory('FlowTodo', function($rootScope, Settings, IbList) {
  var flowTodo = new IbList('/work&type=todo', {
    idAttr: 'runid'
  });

  var reset = angular.bind(flowTodo, flowTodo.reset);

  $rootScope.$on('workflow.handover', reset);
  $rootScope.$on('workflow.handoverFree', reset);
  $rootScope.$on('workflow.signFlow', reset);
  $rootScope.$on('workflow.create', reset);
  $rootScope.$on('workflow.rollback', reset);
  $rootScope.$on('workflow.takeback', reset);
  $rootScope.$on('workflow.remove', function(evt, runid) {
    flowTodo.remove(runid);
  });

  return flowTodo;
})

/**
 * @ngdoc service
 * @name workflow.services.FlowTrans
 * @description
 *   已办结列表数据
 */
.factory('FlowTrans', function($rootScope, Settings, IbList, FlowListUtil) {
  var flowTrans = new IbList('/work&type=trans', {
    idAttr: 'runid'
  });

  angular.extend(flowTrans, FlowListUtil);

  var reset = angular.bind(flowTrans, flowTrans.reset);

  $rootScope.$on('workflow.handover', reset);
  $rootScope.$on('workflow.handoverFree', reset);
  $rootScope.$on('workflow.signFlow', reset);
  $rootScope.$on('workflow.rollback', reset);

  $rootScope.$on('workflow.remove', function(evt, runid) {
    flowTrans.remove(runid);
  });

  $rootScope.$on('workflow.takeback', function(evt, key, res) {
    flowTrans.removeByKey(key);
  });

  return flowTrans;
})

/**
 * @ngdoc service
 * @name workflow.services.FlowDone
 * @description
 *   已完成列表数据
 */
.factory('FlowDone', function($rootScope, Settings, IbList) {
  var flowDone = new IbList('/work&type=done', {
    idAttr: 'runid'
  });

  var reset = angular.bind(flowDone, flowDone.reset);

  $rootScope.$on('workflow.handover', reset);
  $rootScope.$on('workflow.handoverFree', reset);
  $rootScope.$on('workflow.signFlow', reset);
  $rootScope.$on('workflow.rollback', reset);

  $rootScope.$on('workflow.remove', function(evt, runid) {
    flowDone.remove(runid);
  });

  return flowDone;
})

/**
 * @ngdoc service
 * @name workflow.services.FlowFollow
 * @description
 *   我的关注列表数据
 */
.factory('FlowFollow', function($rootScope, Settings, IbList) {
  var flowFollow = new IbList('/work/follow', {
    idAttr: 'runid'
  });

  $rootScope.$on('workflow.remove', function(evt, runid) {
    flowFollow.remove(runid);
  });

  return flowFollow;
})

/**
 * @ngdoc service
 * @name workflow.service.FlowUpload
 * @description
 *  工作流上传处理
 */
.service('FlowUpload', function(Settings, FileUtils, IbPopup, UploadFile, fileSizeFilter, Utils) {
  var This = this;
  this.safeImgTypes = ['gif', 'jpg', 'jpeg', 'png'];
  this.safeFileTypes = ['chm', 'pdf', 'zip', 'rar', 'tar', 'gz', 'bzip2', 'txt', 'doc', 'xls', 'ppt', 'docx', 'xlsx', 'pptx'];

  // 检查是否是支持的文件类型
  this.isSafeFile = function(types, files) {
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      var type = FileUtils.getExtname(file.name).toLowerCase();
      if (types.indexOf(type) === -1) {
        return false;
      }
    }
    return true;
  }

  // 检查空文件
  this.hasEmptyFile = function(files) {
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      if (file.size === 0) {
        return true;
      }
    }
    return false;
  }

  // 检查文件大小
  this.isSafeSize = function(maxSize, files) {
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      if (file.size > maxSize * 1024 * 1024) {
        return false;
      }
    }
    return true;
  }

  this.closeLoading = function($scope, tmp) {
    $scope.$apply(function() {
      tmp.uploading = false;
      tmp.uploaded = true;
    });
  }

  this.upload = function($scope, files, container, processid) {
    angular.forEach(files, function(file) {
      var tmp = {
        filename: file.name,
        filesize: fileSizeFilter(file.size),
        filetype: file.type.split('/')[1],
        delete: true,
        xhr: null,
        uploading: true,
        uploaded: false
      }
      Utils.getImagePreviewUrl(file, function(url) {
        tmp.url = url;
      });
      tmp.index = container.length;
      $scope.$apply(function() {
        container.push(tmp);
      });
      var formData = new FormData();
      formData.append('Filedata[]', file);
      tmp.xhr = UploadFile.upload({
        data: formData,
        params: {
          type: 'workflow',
          flowprocess: processid
        },
        onSuccess: function(res) {
          This.closeLoading($scope, tmp);
          if (res.isSuccess) {
            tmp.aid = res.data[0].aid;
          } else {
            // 删除没上传成功的
            container.splice(tmp.index, 1);
            IbPopup.alert({
              title: res.msg
            });
          }
        },
        onProgress: function(progress) {
          // 进度
          // console.log(progress)
        },
        onFail: function(err) {
          // 删除没上传成功的
          container.splice(tmp.index, 1);
          if (err) {
            var errMsg = err.msg || '上传失败';
            IbPopup.alert({
              title: errMsg
            });
          } else {
            // 上传被取消
          }
        }
      });
    });
  }
})

/**
 * @ngdoc service
 * @name workflow.services.icFactory
 * @description
 *   工作流表单控件处理
 *
 */
.factory('icFactory', function($filter, $timeout, attrFromTemplateFilter, Utils, UserSelector, User) {
  function removeStyle(str) {
    return str ? str.replace(/\s+style=['"].*?['"]/g, '') : '';
  }

  function getIc(id, scope) {
    for (var i in scope.flow.enableArr) {
      var ic = scope.flow.enableArr[i];
      if (ic['data-id'] == id) {
        return ic;
      }
    }
    return null;
  }

  var ics = {
    // 单行文本框
    'text': function(ic, modelName) {
      // 设置了隐藏
      if (ic['data-hide'] == '1') {
        return '<input type="hidden" ng-model="' + modelName + '" name="data_' + ic['data-id'] + '">隐藏字段';
      } else {
        return '<input type="text" ng-model="' + modelName + '" name="data_' + ic['data-id'] + '">';
      }
    },

    // 多行文本框
    'textarea': function(ic, modelName) {
      // 富文本编辑框在手机端上显示为也普通 textarea
      return '<textarea ng-model="' + modelName + ' " name="data_' + ic['data-id'] + '" rows="' + ic['data-rows'] + '" style="width: 100%;"></textarea>';
    },

    // 下拉菜单
    'select': function(ic, modelName, scope) {
      scope.options = ic['data-select-field'].split('`');

      // 如果没有保存值，设置默认选中值
      if (!ic['origin-value']) {
        $timeout(function(){
          scope.setValue(ic['data-id'], ic['data-select-check']);
        }, 100)
      }

      return '<select ng-model="' + modelName + '" ng-init="' + modelName + '= options[0]"  name="data_' + ic['data-id'] + '" size="' + ic['data-size'] + '">' +
        '<option ng-selected="op==' + modelName + '"  value="{{op}}" ng-repeat="op in options">{{op}}</option>' +
        '</select>';
    },

    // 单选
    'radio': function(ic, modelName, scope) {
      scope.radios = ic['data-radio-field'].split('`');

      if (!ic['origin-value']) {
        scope.setValue(ic['data-id'], ic['data-radio-check']);
      }

      // 添加手机端样式
      return '<label class="checkbox" ng-repeat="r in radios">' +
        '<input type="radio" ng-model="' + modelName + '" name="data_' + ic['data-id'] + '" value="{{r}}">' +
        '{{r}}' +
        '</label>';
    },

    // 复选
    'checkbox': function(ic, modelName) {
      return '<label class="checkbox">' +
        '<input type="checkbox" ng-model="' + modelName + '" ng-true-value="\'on\'" ng-false-value="" name="data_' + ic['data-id'] + '">' +
        ic['data-title'] +
        '</label>';
    },

    // 日期选择器
    'date': function(ic, modelName, scope) {
      var dateFilter = $filter('date');
      var isFormTypeSupported = Utils.isFormTypeSupported;
      // 由于 pc 端日期格式为 yyyy-mm-dd hh:ii:ss
      // 此处需要作格式转换
      var dateFormat = ic['data-date-format'].replace('mm', 'MM')
        .replace('hh', 'HH')
        .replace('ii', 'mm'),
        value = ic['origin-value'],
        placeholder = '',
        date,
        type;

      if (value) {
        // 将初始值转换为日期对象
        var dateArr = value.split(/[\-\s\:]/);
        date = new Date(
          dateArr[0],
          dateArr[1] ? +dateArr[1] - 1 : 0,
          dateArr[2] ? +dateArr[2] : 1,
          dateArr[3] ? +dateArr[3] : 0,
          dateArr[4] ? +dateArr[4] : 0,
          dateArr[5] ? +dateArr[5] : 0);
      }

      var isDateType = (dateFormat == 'yyyy-MM-dd' ||
        dateFormat == 'yyyy-MM' ||
        dateFormat == 'yyyy');

      var isDatetimeType = (dateFormat == 'yyyy-MM-dd HH:mm:ss' ||
        dateFormat == 'yyyy-MM-dd HH:mm' ||
        dateFormat == 'yyyy-MM-dd HH');

      // 如果是分类为日期类型且支持日期控件时
      // 使用日期控件并将数据格式化为可用数据
      if (isDateType && isFormTypeSupported('date')) {
        type = 'date';
        if (date) {
          value = date;
        }
        // 如果是分类为日期时间类型且支持日期控件时
      } else if (isDatetimeType && isFormTypeSupported('datetime-local')) {
        type = 'datetime-local';
        if (date) {
          // 时区调整
          value = date;
        }
      } else {
        type = 'text';
        placeholder = '格式为 ' + dateFilter(new Date(), dateFormat);
      }

      // 由于 html5 type 兼容性各种不同，只使用日期和日期时间类型控件来表现各种格式
      // 其他直接使用 text 加 placeholder 提示
      // @todo: 是否不使用原生控件考虑自实现
      var tpl = '<input type="' + type + '" ng-model="' + modelName + '" placeholder="' + placeholder + '" name="data_' + ic['data-id'] + '"/>' +
        '<span class="rp-icon-calendar"></span>';

      scope.setValue(ic['data-id'], value);

      return tpl;
    },

    // 部门人员选择控件
    'user': function(ic, modelName, scope) {
      var selectType = ic['data-select-type'];
      var single = ic['data-single'];
      var userSelector;
      var defaultValue;

      function setModal(modal) {
        userSelector = modal;
      }

      var options = {
        maxSelection: single == 1 ? 1 : false
      };

      if (selectType == 'position') {
        defaultValue = User.removePositionPrefix(scope.ic['origin-value']);
        UserSelector.createPosition(options).then(setModal);

      } else if (selectType == 'department') {
        defaultValue = User.removeDepartmentPrefix(scope.ic['origin-value']);
        UserSelector.createDepartment(options).then(setModal);

      } else {
        defaultValue = User.removePrefix(scope.ic['origin-value']);
        UserSelector.create(options).then(setModal);
      }

      scope.select = function() {
        defaultValue = scope.getValue(ic['data-id']);

        userSelector.show({
            values: defaultValue ? defaultValue.split(',') : [],
          },
          function(selected) {
            scope.setValue(ic['data-id'], selected.join(','));
            userSelector.hide();
          });
      };

      scope.$on('$destroy', function() {
        userSelector.remove();
      });

      scope.setValue(ic['data-id'], defaultValue);

      return '<user-selector select-type="' + ic['data-select-type'] + '" name="data_' + ic['data-id'] + '" ng-model="' + modelName + '"></user-selector> ' +
        '<i class="icon ion-ios-plus positive" ng-click="select()"></i>';
    },

    // 宏控件
    'auto': function(ic, modelName, scope) {
      var template;

      if (!ic['origin-value']) {
        scope.setValue(ic['data-id'], attrFromTemplateFilter(ic.value, 'value'));
      }

      template = removeStyle(ic.value).replace(/<(input|select|textarea)\s+/, function(match) {
        return match + ' ' + 'ng-model="' + modelName + '" ';
      });


      return ic['data-hide'] != 1 ? template : template + '隐藏字段';
    },

    // 计算控件
    'calc': function(ic, modelName, scope) {
      // 设置值精度
      function setPrec(value) {
        return (+value).toFixed(ic['data-prec']);
      }

      var calc = {
        // 获取表单的值
        getVal: function(id) {
          var targetIc = scope.getIc(id);
          var ret = 0;

          if (targetIc && targetIc['data-type'] === 'date') {
            ret = new Date(scope.getValue(id));
          } else if (targetIc && targetIc['data-type'] === 'listview') {
            ret = scope.getValue(id)
          } else {
            ret = parseFloat(scope.getValue(id));
            if (isNaN(ret)) ret = 0;
          }

          return ret;
        },

        // 计算日期
        date: function(value) {
          value = value / 1000;
          return (value >= 0) ?
            Math.floor(value / 86400) + '天' +
            Math.floor((value % 86400) / 3600) + '小时' +
            Math.floor((value % 3600) / 60) + '分' +
            Math.floor(value % 60) + '秒' :
            '时间格式无效';
        },

        // 天数计算
        day: function(val) {
          return setPrec(val <= 0 ? 0 : Math.floor(val / 86400000));
        },

        // 小时
        hour: function(val) {
          return setPrec(val <= 0 ? 0 : Math.floor(val / 3600000));
        },

        sum: function() {
          if (arguments.length === 0) {
            return '';
          }
          var argu = arguments;
          var total = 0;
          for (var i = 0; i < argu.length; i++) {
            total += argu[i]
          }
          return setPrec(parseFloat(total))
        },

        // 最大值
        max: function() {
          if (arguments.length === 0) {
            return '';
          }
          return setPrec(parseFloat(Math.max.apply(null, arguments)));
        },

        // 最小值
        min: function() {
          if (arguments.length === 0) {
            return '';
          }
          return setPrec(parseFloat(Math.min.apply(null, arguments)));
        },

        // 取模运算
        mod: function() {
          if (arguments.length === 0) {
            return;
          }
          var firstNum = arguments[0];
          var secondNum = arguments[1];
          var result = firstNum % secondNum;
          result = isNaN(result) ? "" : parseFloat(result);
          return setPrec(result);
        },

        // 绝对值
        abs: function(val) {
          return setPrec(Math.abs(parseFloat(val)));
        },

        // 平均值
        avg: function() {
          var value = 0;
          var len = arguments.length;

          for (var i = 0; i < len; i++) {
            value += parseFloat(arguments[i] || 0);
          }

          return setPrec(value / len);
        },

        // 人民币计算大写
        rmb: function(currencyDigits) {
          // Constants:
          var MAXIMUM_NUMBER = 99999999999.99;
          // Variables:
          var integral; // Represent integral part of digit number.
          var decimal; // Represent decimal part of digit number.
          var outputCharacters; // The output result.
          var parts;
          var digits, radices, bigRadices, decimals;
          var zeroCount;
          var i, p, d;
          var quotient, modulus;
          // Validate input string:
          currencyDigits = currencyDigits.toString();
          if (currencyDigits == "") {
            return "";
          }
          if (currencyDigits.match(/[^,.\d]/) != null) {
            return "";
          }
          if ((currencyDigits).match(/^((\d{1,3}(,\d{3})*(.((\d{3},)*\d{1,3}))?)|(\d+(.\d+)?))$/) == null) {
            return "";
          }
          // Normalize the format of input digits:
          currencyDigits = currencyDigits.replace(/,/g, ""); // Remove comma delimiters.
          currencyDigits = currencyDigits.replace(/^0+/, ""); // Trim zeros at the beginning.
          // Assert the number is not greater than the maximum number.
          if (Number(currencyDigits) > MAXIMUM_NUMBER) {
            return "";
          }
          // Process the coversion from currency digits to characters:
          // Separate integral and decimal parts before processing coversion:
          parts = currencyDigits.split(".");
          if (parts.length > 1) {
            integral = parts[0];
            decimal = parts[1];
            // Cut down redundant decimal digits that are after the second.
            decimal = decimal.substr(0, 2);
          } else {
            integral = parts[0];
            decimal = "";
          }
          // Prepare the characters corresponding to the digits:
          digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
          radices = ['', '拾', '佰', '仟'];
          bigRadices = ['', '万', '亿'];
          decimals = ['角', '分'];
          // Start processing:
          outputCharacters = "";
          // Process integral part if it is larger than 0:
          if (Number(integral) > 0) {
            zeroCount = 0;
            for (i = 0; i < integral.length; i++) {
              p = integral.length - i - 1;
              d = integral.substr(i, 1);
              quotient = p / 4;
              modulus = p % 4;
              if (d == "0") {
                zeroCount++;
              } else {
                if (zeroCount > 0) {
                  outputCharacters += digits[0];
                }
                zeroCount = 0;
                outputCharacters += digits[Number(d)] + radices[modulus];
              }
              if (modulus == 0 && zeroCount < 4) {
                outputCharacters += bigRadices[quotient];
              }
            }
            outputCharacters += '元';
          }
          // Process decimal part if there is:
          if (decimal != "") {
            for (i = 0; i < decimal.length; i++) {
              d = decimal.substr(i, 1);
              if (d != "0") {
                outputCharacters += digits[Number(d)] + decimals[i];
              }
            }
          }
          // Confirm and return the final output string:
          if (outputCharacters == "") {
            outputCharacters = '零元';
          }
          if (decimal == "") {
            outputCharacters += '整';
          }
          //outputCharacters = CN_SYMBOL + outputCharacters;
          return outputCharacters;
        },

        // 列表控件计算
        // @todo: 手机端暂时不支持列表控件
        list: function(val, row) {
          // console.log(val, row);
          var output = 0
          val.split("\n").map(function(item) {
            item.split('`').map(function(_item, _index) {
              if (_index === (row - 1)) {
                output += parseFloat(_item)
              }
            })
          })

          return output
        }
      };

      // 获取计算表达式
      var exp = attrFromTemplateFilter(ic.value, 'data-exp');
      var icIds = exp ? exp.match(/\d+/g) : null;
      if (icIds) {
        // 监控计算控件相关的字段的变化情况
        scope.$watch(function () {
          return icIds.map(function(icId) {
            return scope.getValue(icId);
          }).join();
        }, function() {
          try {
            var evalExp = eval(exp);
            scope.setValue(ic['data-id'], typeof evalExp == "number" ? evalExp.toFixed(ic['data-prec']) : evalExp);
          } catch (e) {

          }
        });
      }

      return '<input type="text" ng-model="' + modelName + '" name="data_' + ic['data-id'] + '" />';
    },

    // 图片上传控件
    'imgupload': function(ic, modelName) {
      var src = attrFromTemplateFilter(ic.value, 'data-src');
      //return src ? '<img src="' + $filter('fullUrl')(src) + '" width="' + ic['data-width'] + '" height="' + ic['data-height'] + '"/>' : '<span>';
      return '<span>暂不支持图片上传控件</span>';
    },

    // 列表控件
    'listview': function(ic, modelName) {
      return '<span>暂不支持列表控件</span>';
    },

    // 签章控件
    'sign': function(ic, modelName) {
      return '<span>暂不支持签章控件</span>';
    },

    // 进度条控件
    'progressbar': function(ic, modelName) {
      return '<span>暂不支持进度条控件</span>';
    },

    'qrcode': function(ic, modelName) {
      return '<span>暂不支持二维码控件</span>';
    }
  };

  var ret = {
    parse: function(ic, scope, pattern) {
      var type = ic && ic['data-type'];
      if (!ics[type]) {
        return ic.value || '';
      }

      return ics[type].call(null, ic, scope, pattern);
    }
  };

  ret.serializes = {
    // 日期控件
    date: function(value, field) {
      if (!value) {
        return '';
      }

      var format = field['data-date-format'].replace('mm', 'MM')
        .replace('hh', 'HH')
        .replace('ii', 'mm');

      var date;

      if (
        Utils.isFormTypeSupported('datetime-local') ||
        Utils.isFormTypeSupported('date')
      ) {
        return $filter('date')(value, format);
      }

      return value;
    },

    // 部门人员控件
    user: function(value, field) {
      var selectType = field['data-select-type'];

      if (selectType == 'user') {
        return User.addPrefix(value);
      } else if (selectType == 'position') {
        return User.addPositionPrefix(value);
      } else {
        return User.addDepartmentPrefix(value);
      }
    },

    //图片上传控件
    //imgupload: function(value, field) {
    //  if(!value) {
    //    return '';
    //  }
    //
    //  var formData = new FormData();
    //  var file = value[0];
    //  formData.append('data_' + field['data-id'], file);
    //
    //  return formData;
    //}
  };

  // 标准化要提交的控件数据
  ret.serialize = function(data, fields) {
    if (!fields || !fields.length) {
      return data;
    }

    angular.forEach(fields, function(field) {
      var type = field['data-type'];
      var id = field['data-id'];

      if (ret.serializes[type]) {
        data['data_' + id] = ret.serializes[type].call(null, data['data_' + id], field);
      }
    });

    return data;
  };

  return ret;
})
